#include "serialportcontroller.h"
#include "protocolhandler.h"
#include "communicationlogger.h"
#include <QSerialPortInfo>
#include <QDataStream>
#include <QSettings>

SerialPortController::SerialPortController(QObject *parent)
    : QObject(parent)
    , m_serialPort(new QSerialPort(this))
    , m_protocolHandler(new ProtocolHandler(this))
    , m_logger(new CommunicationLogger(this))
    , m_responseTimer(new QTimer(this))
    , m_isConnected(false)
    , m_targetModuleId(0x02)
    , m_frameCounter(0)
    , m_currentFocusStep(0)
    , m_motorTotalTravel(0)
    , m_baudRate(460800)
    , m_dataBits(QSerialPort::Data8)
    , m_parity(QSerialPort::NoParity)
    , m_stopBits(QSerialPort::OneStop)
    , m_flowControl(QSerialPort::NoFlowControl)
    , m_imageClarity(5000)
{
    // Connect serial port signals
    connect(m_serialPort, &QSerialPort::readyRead, this, &SerialPortController::handleReadyRead);
    connect(m_serialPort, &QSerialPort::errorOccurred, this, &SerialPortController::handleError);
    
    // Connect protocol handler signals
    connect(m_protocolHandler, &ProtocolHandler::frameReceived, 
            this, &SerialPortController::handleFrameReceived);
    connect(m_protocolHandler, &ProtocolHandler::frameError,
            this, &SerialPortController::handleFrameError);
    
    // Setup response timeout timer (2 seconds)
    m_responseTimer->setSingleShot(true);
    m_responseTimer->setInterval(20000);//暂时使用20s方便测试
    connect(m_responseTimer, &QTimer::timeout, this, &SerialPortController::handleResponseTimeout);
    
    refreshPorts();
    loadSettings();
}

SerialPortController::~SerialPortController()
{
    saveSettings();
    closePort();
}

void SerialPortController::setCurrentPort(const QString &port)
{
    if (m_currentPort != port) {
        m_currentPort = port;
        emit currentPortChanged();
    }
}

void SerialPortController::setTargetModuleId(quint8 id)
{
    if (m_targetModuleId != id) {
        m_targetModuleId = id;
        emit targetModuleIdChanged();
        
        // Clear status when switching modules
        m_workStatus = "";
        m_selfCheckStatus = "";
        m_focusMode = "";
        m_brakeStatus = "";
        m_currentFocusStep = 0;
        m_motorTotalTravel = 0;
        
        emit workStatusChanged();
        emit selfCheckStatusChanged();
        emit focusModeChanged();
        emit brakeStatusChanged();
        emit currentFocusStepChanged();
        emit motorTotalTravelChanged();
        
        // Log module switch
        m_logger->logInfo(QString("Switched to module 0x%1").arg(id, 2, 16, QChar('0')).toUpper());
    }
}

void SerialPortController::setBaudRate(qint32 baudRate)
{
    if (m_baudRate != baudRate) {
        m_baudRate = baudRate;
        emit baudRateChanged();
    }
}

void SerialPortController::setDataBits(int dataBits)
{
    if (m_dataBits != dataBits) {
        m_dataBits = dataBits;
        emit dataBitsChanged();
    }
}

void SerialPortController::setParity(int parity)
{
    if (m_parity != parity) {
        m_parity = parity;
        emit parityChanged();
    }
}

void SerialPortController::setStopBits(int stopBits)
{
    if (m_stopBits != stopBits) {
        m_stopBits = stopBits;
        emit stopBitsChanged();
    }
}

void SerialPortController::setFlowControl(int flowControl)
{
    if (m_flowControl != flowControl) {
        m_flowControl = flowControl;
        emit flowControlChanged();
    }
}

void SerialPortController::setImageClarity(quint16 clarity)
{
    if (m_imageClarity != clarity) {
        m_imageClarity = clarity;
        emit imageClarityChanged();
    }
}

void SerialPortController::refreshPorts()
{
    m_availablePorts.clear();
    
    const auto ports = QSerialPortInfo::availablePorts();
    for (const QSerialPortInfo &info : ports) {
        m_availablePorts.append(info.portName());
    }
    
    emit availablePortsChanged();
}

bool SerialPortController::openPort()
{
    if (m_currentPort.isEmpty()) {
        emit errorOccurred("No port selected");
        return false;
    }
    
    if (m_isConnected) {
        closePort();
    }
    
    m_serialPort->setPortName(m_currentPort);
    m_serialPort->setBaudRate(m_baudRate);
    m_serialPort->setDataBits(static_cast<QSerialPort::DataBits>(m_dataBits));
    m_serialPort->setParity(static_cast<QSerialPort::Parity>(m_parity));
    m_serialPort->setStopBits(static_cast<QSerialPort::StopBits>(m_stopBits));
    m_serialPort->setFlowControl(static_cast<QSerialPort::FlowControl>(m_flowControl));
    
    if (m_serialPort->open(QIODevice::ReadWrite)) {
        updateConnectionState(true);
        m_logger->logInfo(QString("Connected to %1").arg(m_currentPort));
        return true;
    } else {
        emit errorOccurred(QString("Failed to open port %1: %2")
                          .arg(m_currentPort)
                          .arg(m_serialPort->errorString()));
        return false;
    }
}

void SerialPortController::closePort()
{
    if (m_serialPort->isOpen()) {
        m_serialPort->close();
        updateConnectionState(false);
        m_logger->logInfo(QString("Disconnected from %1").arg(m_currentPort));
    }
}

void SerialPortController::sendManualFocusPlus(quint8 stepLevel)
{
    QByteArray params;
    params.append(static_cast<char>(stepLevel));
    sendCommand(static_cast<quint8>(FocusCommand::ManualFocusPlus), params);
}

void SerialPortController::sendManualFocusMinus(quint8 stepLevel)
{
    QByteArray params;
    params.append(static_cast<char>(stepLevel));
    sendCommand(static_cast<quint8>(FocusCommand::ManualFocusMinus), params);
}

void SerialPortController::sendSetFocusValue(quint16 focusValue)
{
    QByteArray params;
    QDataStream stream(&params, QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::LittleEndian);
    stream << focusValue;
    sendCommand(static_cast<quint8>(FocusCommand::SetFocusValue), params);
}

void SerialPortController::sendBrake()
{
    sendCommand(static_cast<quint8>(FocusCommand::Brake), QByteArray());
}

void SerialPortController::sendBrakeRelease()
{
    sendCommand(static_cast<quint8>(FocusCommand::BrakeRelease), QByteArray());
}

void SerialPortController::sendAutoFocus(quint16 imageClarity)
{
    // Image clarity is now in the dedicated field, send empty params (will be padded with 0x00 0x00)
    sendCommand(static_cast<quint8>(FocusCommand::AutoFocus), QByteArray());
}

void SerialPortController::sendReset()
{
    sendCommand(static_cast<quint8>(FocusCommand::Reset), QByteArray());
}

void SerialPortController::sendQuery()
{
    sendCommand(0x00, QByteArray());
}

void SerialPortController::handleReadyRead()
{
    QByteArray data = m_serialPort->readAll();
    
    // Log received data
    m_logger->logFrame(CommunicationLogger::RX, data);
    
    // Pass to protocol handler for parsing
    m_protocolHandler->processIncomingData(data);
}

void SerialPortController::handleError(QSerialPort::SerialPortError error)
{
    // Ignore NoError
    if (error == QSerialPort::NoError) {
        return;
    }
    
    QString errorMsg;
    
    switch (error) {
    case QSerialPort::DeviceNotFoundError:
        errorMsg = "Device not found";
        break;
    case QSerialPort::PermissionError:
        errorMsg = "Permission denied";
        break;
    case QSerialPort::OpenError:
        errorMsg = "Failed to open port";
        break;
    case QSerialPort::WriteError:
        errorMsg = "Write error";
        break;
    case QSerialPort::ReadError:
        errorMsg = "Read error";
        break;
    case QSerialPort::ResourceError:
        errorMsg = "Resource error (device disconnected?)";
        // Handle unexpected disconnection
        if (m_isConnected) {
            closePort();
            m_logger->logError("Unexpected disconnection detected");
        }
        break;
    case QSerialPort::TimeoutError:
        errorMsg = "Timeout error";
        break;
    default:
        errorMsg = QString("Serial port error: %1").arg(m_serialPort->errorString());
        break;
    }
    
    m_logger->logError(errorMsg);
    emit errorOccurred(errorMsg);
}

void SerialPortController::handleFrameReceived(quint8 sourceId, quint8 command, quint8 workStatus,
                                               qint16 currentStep, qint16 totalTravel)
{
    // Stop timeout timer since we received a response
    m_responseTimer->stop();
    
    // Only update status if the response is from the currently selected target module
    if (sourceId != m_targetModuleId) {
        // Log that we received a response from a different module
        m_logger->logError(QString("Received response from module 0x%1, but current target is 0x%2")
                          .arg(sourceId, 2, 16, QChar('0'))
                          .arg(m_targetModuleId, 2, 16, QChar('0')));
        return;
    }
    
    // Decode work status bits
    WorkStatus status = WorkStatus::fromByte(workStatus);
    
    // Update combined status text (for backward compatibility)
    QString statusText = QString("自检: %1 | 模式: %2 | 抱闸: %3")
        .arg(status.selfCheckPassed ? "成功" : "失败")
        .arg(status.autoFocusMode ? "自动" : "手动")
        .arg(status.brakeEngaged ? "抱闸" : "未抱闸");
    
    if (m_workStatus != statusText) {
        m_workStatus = statusText;
        emit workStatusChanged();
    }
    
    // Update individual status properties
    QString selfCheck = status.selfCheckPassed ? "成功" : "失败";
    if (m_selfCheckStatus != selfCheck) {
        m_selfCheckStatus = selfCheck;
        emit selfCheckStatusChanged();
    }
    
    QString mode = status.autoFocusMode ? "自动" : "手动";
    if (m_focusMode != mode) {
        m_focusMode = mode;
        emit focusModeChanged();
    }
    
    QString brake = status.brakeEngaged ? "抱闸" : "未抱闸";
    if (m_brakeStatus != brake) {
        m_brakeStatus = brake;
        emit brakeStatusChanged();
    }
    
    if (m_currentFocusStep != currentStep) {
        m_currentFocusStep = currentStep;
        emit currentFocusStepChanged();
    }
    
    if (m_motorTotalTravel != totalTravel) {
        m_motorTotalTravel = totalTravel;
        emit motorTotalTravelChanged();
    }
}

void SerialPortController::handleFrameError(const QString &error)
{
    m_logger->logError(QString("Protocol error: %1").arg(error));
    emit errorOccurred(error);
}

void SerialPortController::sendCommand(quint8 command, const QByteArray &params)
{
    if (!m_isConnected) {
        emit errorOccurred("Cannot send command: not connected");
        return;
    }
    
    // Build frame using protocol handler
    QByteArray frame = m_protocolHandler->buildCommandFrame(
        SOURCE_ID_DISPLAY,
        m_targetModuleId,
        m_frameCounter,
        command,
        params,
        m_imageClarity
    );
    
    // Increment frame counter (0-255 cycling)
    m_frameCounter = (m_frameCounter + 1) % 256;
    
    // Send frame
    qint64 bytesWritten = m_serialPort->write(frame);
    if (bytesWritten == -1) {
        emit errorOccurred(QString("Failed to write to serial port: %1")
                          .arg(m_serialPort->errorString()));
        return;
    }
    
    // Log sent frame
    m_logger->logFrame(CommunicationLogger::TX, frame);
    
    // Start response timeout timer
    m_responseTimer->start();
}

void SerialPortController::handleResponseTimeout()
{
    QString timeoutMsg = "Response timeout: No response received within 2 seconds";
    m_logger->logError(timeoutMsg);
    emit errorOccurred(timeoutMsg);
}

void SerialPortController::updateConnectionState(bool connected)
{
    if (m_isConnected != connected) {
        m_isConnected = connected;
        emit isConnectedChanged();
    }
}

void SerialPortController::loadSettings()
{
    QSettings settings;
    
    // Load last used port
    QString lastPort = settings.value("serialPort/lastPort", "").toString();
    if (!lastPort.isEmpty() && m_availablePorts.contains(lastPort)) {
        setCurrentPort(lastPort);
    }
    
    // Load last used module ID
    quint8 lastModuleId = settings.value("serialPort/lastModuleId", 0x02).toUInt();
    setTargetModuleId(lastModuleId);
    
    // Load serial port configuration
    setBaudRate(settings.value("serialPort/baudRate", 460800).toInt());
    setDataBits(settings.value("serialPort/dataBits", QSerialPort::Data8).toInt());
    setParity(settings.value("serialPort/parity", QSerialPort::NoParity).toInt());
    setStopBits(settings.value("serialPort/stopBits", QSerialPort::OneStop).toInt());
    setFlowControl(settings.value("serialPort/flowControl", QSerialPort::NoFlowControl).toInt());
}

void SerialPortController::saveSettings()
{
    QSettings settings;
    
    // Save current port
    settings.setValue("serialPort/lastPort", m_currentPort);
    
    // Save current module ID
    settings.setValue("serialPort/lastModuleId", m_targetModuleId);
    
    // Save serial port configuration
    settings.setValue("serialPort/baudRate", m_baudRate);
    settings.setValue("serialPort/dataBits", m_dataBits);
    settings.setValue("serialPort/parity", m_parity);
    settings.setValue("serialPort/stopBits", m_stopBits);
    settings.setValue("serialPort/flowControl", m_flowControl);
}
